/*
 * @Author: xudc
 * @Date: 2021-03-24 09:16:00
 * @LastEditTime: 2021-03-26 00:03:46
 * @LastEditors: xudc
 * @Description: In User Settings Edit
 * @FilePath: /000/lagouXudc/lagou-xudc-task/part1/fed-e-task-01-01/code/MyPromise.js
 */
/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
手写promise的功能列表如下：
1. Promise 是个类。构造函数接收执行器，执行器入参为resolve和reject，立即执行。
2. Promise中有三个状态，成功fulfilled 失败 rejected 等待 pending。pending 一旦转变为fulfilled或者rejected 便不可更改。
3. resolve 和 reject 函数是用来更改Promise状态的。
4. then 方法内部做的事情就是判断状态，状态为fulfilled则调用传入的成功的回调。 失败则调用失败的回调。
5. then 方法是定义在原型对象中的
6. Then方法的成功回调函数有一个入参，表示状态为成功后的值。 失败状态也有一个入参，表示原因。
7. Promise类里得有异步处理逻辑。也就是resolve 和reject方法有异步处理逻辑。
8. Promise实例对象可以执行多次then方法
9. then方法可以链式调用
10. then方法的入参是可选参数，若入参为空则把上一个promise结果传递给下一层then
11. Promise.all 
12. Promise.resolve
13. Promise.reject
14. finally方法
16. catch方法
*/

const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
    // 立即执行函数-执行器
    constructor(exector) {
        exector(this.resolve, this.reject);
    }
    // promise状态，默认为pending
    status = PENDING;
    
    // 成功之后的值
    value = undefined;
    // 失败之后的原因
    reason = undefined;
    // 成功回调
    succesCallback = [];
    // 失败回调
    failCallback = [];

    resolve = value => {
        // 如果状态不是等待，阻止程序向下执行
        if(this.status !== PENDING) return;
        // 将状态更改为成功
        this.status = FULFILLED;
        // 保存成功之后的值
        this.value = value;
        // 判断成功回调是否存在，如果存在调用
        // then方法调用多次处理函数情况
        while(this.successcallback.length) {
            this.succesCallback.shift()(this.value);
        }
    }
    
    reject = reason => {
        // 如果状态不是等待，阻止程序向下执行
        if(this.status !== PENDING) return;
        // 将状态更改为 失败
        this.status = REJECTED;
        // 保存成失败之后的原因
        this.reason = reason;
        // 判断失败回调是否存在，如果存在调用
        // then方法调用多次处理函数情况
        while(this.failCallback.length) {
            this.failCallback.shift()(this.reason);
        }
    }

    then(successCallback, failcCallback) {
        successCallback = successCallback ? successCallback : val => val; // 当成功回调函数为空或者undefined的时候，直接返回promi的值
        failcCallback = failcCallback ? failcCallback : reason => { throw reason; }; // 当失败回调函数为空或者undefined的时候，直接使用throw抛出错误

        let _promise = new MyPromise((resolve, reject) => { // then方法可以链式调用. return MyPromise实例对象
            if (this.status === FULFILLED) {

                try { // 捕捉成功回调方法的异常
                    setTimeout(() => {
                        let val = successCallback(this.value);
                        resolvePromise(_promise, val, resolve, reject);
                    }, 0);
                } catch (error) {
                    reject(error);
                }

            } else if (this.status === REJECTED) {

                try {// 捕捉失败回调方法的异常
                    setTimeout(() => {
                        let val = failCallback(this.reason);
                        resolvePromise(_promise, val, resolve, reject);
                    }, 0);

                } catch (error) {
                    reject(error);
                }

            } else {
                this.successCallback.push(() => {
                    try { // 捕捉成功回调方法的异常
                        setTimeout(() => {
                            let val = successCallback(this.value);
                            resolvePromise(_promise, val, resolve, reject);
                        }, 0);

                    } catch (error) {
                        reject(error);
                    }
                }); // then方法可以被多次调用

                this.failCallback.push(() => {
                    try {// 捕捉失败回调方法的异常
                        setTimeout(() => {
                            let val = failCallback(this.reason);
                            resolvePromise(_promise, val, resolve, reject);
                        }, 0);

                    } catch (error) {
                        reject(error);
                    }
                }); // then方法可以被多次调用
            }
        })
        return _promise;
    }

    static all(arr) { // 静态方法 all 实现
        let list = [];
        let count = 0;
        return new MyPromise((resolve, reject) => {
            const addInList = (index, value) => {
                list[index] = value;
                count++;
                if (count === arr.length) {
                    resolve(list);
                }
            }
            arr.map((item, index) => {
                if (item instanceof MyPromise) {
                    item.then((val) => {
                        addInList(index, val);
                    }, (reason) => {
                        reject(reason);
                    })
                } else {
                    addInList(index, item);
                }
            });
        });
    }

    static resolve(value) { // 静态方法 resolve 实现
        if (value instanceof MyPromise) return value; // 判断插传入对象
        return new MyPromise(resolve => resolve(value));
    }

    static reject(value) { // 静态方法 resolve 实现
        return new MyPromise((resolve,rejcet) => rejcet(value));
    }

    finally(callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason });
        })
    }

    catch(failCallback) {
        return this.then(undefined, failCallback);
    }
}

function resolvePromise(_promise, val, resolve, reject) {
    if (_promise === val) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
    }
    if (val instanceof MyPromise) {
        val.then(resolve, reject);
    } else {
        // 非MyPromis实例对象
        resolve(val);
    }
}

modules.export = MyPromise;